package com.bocomm.tracevisualization.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bocomm.tracevisualization.api.result.CodeMessage;
import com.bocomm.tracevisualization.api.service.ITerminalManagementService;
import com.bocomm.tracevisualization.global.BusinessException;
import com.bocomm.tracevisualization.job.MyJob;
import com.bocomm.tracevisualization.mapper.TerminalManagementMapper;
import com.bocomm.tracevisualization.api.entity.TerminalManagement;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.TimeZone;

import static com.bocomm.tracevisualization.core.CmdExecutor.fetchLocalHostIp;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author cxp
 * @since 2024-03-20
 */
@Service
@Slf4j
public class TerminalManagementServiceImpl extends ServiceImpl<TerminalManagementMapper, TerminalManagement> implements ITerminalManagementService {


    @Autowired
    private Scheduler scheduler;
    /**
     * 保存或更新终端管理信息，并进行重复性校验。
     * @param terminalManagement 终端管理对象，包含终端的相关信息。
     * 该方法首先检查终端IP是否为空，若为空则直接返回。
     * 对于新添加的终端，会校验该IP是否已存在；对于更新的终端，不进行重复性校验。
     * 若终端IP不存在，则保存或更新该终端信息。
     */
    @Override
    public void saveOrUpdateAndChack(TerminalManagement terminalManagement) throws SchedulerException {

        String terminalIp = terminalManagement.getTerminalIp();
        if(!StringUtils.hasText(terminalIp)){
            return ;
        }
        QueryWrapper<TerminalManagement> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TerminalManagement::getTerminalIp,terminalIp);
        if(null == terminalManagement.getId()){
            int count = count(queryWrapper);
            if(count>0){
                throw new BusinessException(CodeMessage.VALIDATE_ERROR.fillArgs("终端Ip重复"));
            }
        }
        terminalManagement.setActive(false);
        deleteSchedule(terminalIp);
        saveOrUpdate(terminalManagement);
    }

    @Override
    @Transactional
    public void active(TerminalManagement updateObject, String terminalIp) throws SchedulerException {
        Boolean active = updateObject.getActive();
        TerminalManagement terminalManagement = getById(updateObject.getId());
        if(null == terminalManagement){
            throw new BusinessException(CodeMessage.VALIDATE_ERROR.fillArgs("终端信息不存在"));
        }
        if(!terminalManagement.getTerminalIp().equals(terminalIp)){
            throw new BusinessException(CodeMessage.VALIDATE_ERROR.fillArgs("终端信息不一致"));
        }
        if(active){
            if(terminalManagement.getActive()){
                throw new BusinessException(CodeMessage.VALIDATE_ERROR.fillArgs("终端Ip已激活"));
            }
            terminalManagement.setActive(true);

        }else{
            if(!terminalManagement.getActive()){
                throw new BusinessException(CodeMessage.VALIDATE_ERROR.fillArgs("终端Ip未激活"));
            }
        }

        registerSchedule(terminalManagement,active);
        updateById(updateObject);

    }

    @Override
    @Transactional
    public void deleteConfig(Integer id) throws SchedulerException {
        TerminalManagement terminalManagement = getById(id);

        if(null == terminalManagement){
            throw new BusinessException(CodeMessage.VALIDATE_ERROR.fillArgs("终端信息不存在"));
        }
        deleteSchedule(terminalManagement.getTerminalIp());
        removeById(id);
    }

    private void registerSchedule(TerminalManagement terminalManagement, Boolean active) throws SchedulerException {
        for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.groupEquals("terminalTask"))) {
            if(jobKey.getName().equals(fetchLocalHostIp()+"_"+terminalManagement.getTerminalIp())){
                if(active){
                    scheduler.resumeJob(jobKey);
                }else{
                    scheduler.pauseJob(jobKey);
                }
                return;
            }
        }
        if(active){
            createSchedule(terminalManagement);
        }
    }
    /**
     * 创建一个调度任务，用于管理指定终端的采样任务。
     *
     * @param terminalManagement 终端管理对象，包含终端的IP地址、采样率、延迟阈值和超时阈值。
     * @throws SchedulerException 如果调度过程中发生错误。
     */
    private void createSchedule(TerminalManagement terminalManagement) throws SchedulerException {
        // 从终端管理对象中获取终端IP、采样率、延迟阈值和超时阈值
        String terminalIp = terminalManagement.getTerminalIp();
        Integer samplingRate = terminalManagement.getSamplingRate() ;
        Double delayThreshold = terminalManagement.getDelayThreshold();
        Integer timeoutThreshold = terminalManagement.getTimeoutThreshold();

        // 创建一个作业数据映射，用于传递给作业的参数
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("terminalIp",terminalIp);
        jobDataMap.put("delayThreshold",delayThreshold);
        jobDataMap.put("samplingRate",samplingRate);
        jobDataMap.put("timeoutThreshold",timeoutThreshold);


        // 构建作业详情，指定作业类、作业标识和传递给作业的数据
        JobDetail job = JobBuilder.newJob(MyJob.class)
                .withIdentity(fetchLocalHostIp()+"_"+terminalIp, "terminalTask")
                .setJobData(jobDataMap)
                .build();

        // 构建触发器，指定触发器的启动时间、调度策略（使用CRON表达式）和时区
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(fetchLocalHostIp()+"_"+terminalIp, "terminalTask")
                .startNow()
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(samplingRate)
                        .withMisfireHandlingInstructionNextWithRemainingCount()
                        .repeatForever()
                )//错过策略
                .build();

        // 在调度器中安排作业执行
        scheduler.scheduleJob(job,trigger);
    }

    private void deleteSchedule(String terminalIp) throws SchedulerException {

        for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.groupEquals("terminalTask"))) {
            if(jobKey.getName().equals(fetchLocalHostIp()+"_"+terminalIp)){
                scheduler.deleteJob(jobKey);
                return;
            }
        }
    }
}
